package net.fkrahe.graph;

import java.util.Iterator;
import java.util.LinkedList;

/**
 * Class WLinked Graph (Weighted Linked Graph)
 * 
 * @author Yedidyah Langsan | Moshe Augenstein | Aaron M. Tenenbaum
 */
public class WLinkedGraph extends Graph {

    public WLinkedGraph() {
        super();
    }

    /**
     * Creates an arc between node1 and node2 with the given weight
     * 
     * @param node1
     * @param node2
     * @param weight 
     */
    public void join(Object node1, Object node2, int weight) {
        GraphNode gn1 = findNode(node1);
        GraphNode gn2 = findNode(node2);
        LinkedList<ArcNode> arcList = gn1.getArcptr();
        WArcNode arcNode = new WArcNode(gn2, weight);

        // If the graph node is not connected to anything, create the arc
        if (arcList == null) {
            LinkedList<ArcNode> list = new LinkedList<ArcNode>();
            list.addFirst(arcNode);
            gn1.setArcptr(list);
        } else if (arcList.isEmpty()) {
            arcList.addFirst(arcNode);
        } else {

            Iterator<ArcNode> itrWAn = arcList.iterator();
            while (itrWAn.hasNext()) {
                WArcNode tmp = (WArcNode) itrWAn.next();
                if (tmp.getPtr() == gn2) {
                    arcNode.setWeight(weight);
                    return;
                }
            }
            // connect node1 and node2
            arcList.addLast(arcNode);
        }
    }

    /**
     * Returns the weight on the arc between node1 and node2.
     * If node1 is not connected to node2 throws a WLinkedGraphException
     * 
     * @param node1
     * @param node2
     * @return
     * @throws WLinkedGraphException 
     */
    public int remove(Object node1, Object node2)
            throws WLinkedGraphException {
        // if node1 is not adjacent to node2, throw an exception
        if (!adjacent(node1, node2)) {
            throw new WLinkedGraphException(node1.toString() + " is not connected to " + node2.toString());
        }

        int w = getWeight(node1, node2);
        GraphNode gn1 = findNode(node1);
        GraphNode gn2 = findNode(node2);
        LinkedList<ArcNode> arcList = gn1.getArcptr();
        // node1 is not connected to anything, so there is
        // nothing to remove
        if (arcList == null || arcList.isEmpty()) {
            throw new WLinkedGraphException(node1.toString() + " is not connected to any other node.");
        }
        arcList.remove(new WArcNode(gn2, 0));
        return w;
    }

    /**
     * Return the weight on the arc between node1 and node2.
     * If node1 is not connected to node2 throws a
     * WLinkedGraphException
     * 
     * @param node1
     * @param node2
     * @return
     * @throws WLinkedGraphException 
     */
    public int getWeight(Object node1, Object node2) throws WLinkedGraphException {
        GraphNode gn1 = findNode(node1);
        GraphNode gn2 = findNode(node2);
        LinkedList<ArcNode> arcList = gn1.getArcptr();
        Iterator<ArcNode> itr = arcList.iterator();

        while (itr.hasNext()) {
            WArcNode arcNode = (WArcNode) itr.next();
            if (arcNode.getPtr() == gn2) {
                return arcNode.getWeight();
            }
        }
        // node 1 and node 2 are not connected
        throw new WLinkedGraphException(node1.toString() + " is not connected to " + node2.toString());
    }
}
